/*
   Represents a computational grid.
*/

#ifndef ARRAY_HPP
#define ARRAY_HPP
#include "Debug.hpp"
#include "Types.hpp"
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <iomanip>
#include <iostream>
#include <cmath>
#include <functional>

class Array {
private:
    size_t width_;
    real h_;
    real * array_dyn;
public:
    // Constructor 2D
    explicit Array(size_t level)
    {
        width_= pow(2,level)+1;
        h_ = 1.0/(width_-1.0);
        array_dyn = new real [width_*width_]();
    }
    // Default Constructor
    Array();
    //copy Constructor
    Array(const Array& s);
    //assignment  Operator
    Array& operator= (const Array& s);

    ~Array()
    {
        delete[] array_dyn;
    }

    // Operator() 2D
    inline real& operator ()(int i,int j) // i is row number, j is column number
    {
        ASSERT ((i < width_ && j < width_) , Trying to access out of Bound Array);
        return array_dyn[i*width_+j];
    }
    // Operator() 2D
    inline real operator()(int i,int j) const // i is row number, j is column number
    {
        ASSERT ((i < width_ && j < with_) , Trying to access out of Bound Array);
        return array_dyn[i*width_+j];
    }

    //initialize the whole array with an value
    void fill(const real& in);

    //return the width of the array
    inline const size_t& xsize() const {
        return width_;
    }

    //return total size of the array
    inline const real& hSize() const {
        return h_;
    }

    // print the whole array (for debugging purposes)
    void print(std::ostream& out);
    void printGNUPLOT(std::ostream& out);

    void resize( size_t level);
    //Compute the L2 norm
    real l2Norm() const;
    //set a value to all boundaries
    void setAllDirichletBoundary(std::function<real(real,real)> g);
    //set a value to an specific boundary
    void setDirichletBoundary(std::function<real(real,real)> g, BOUNDARY bound);

};
#endif //ARRAY_HH

